import React, { Component } from "react";

interface IProps {
  startDom: HTMLElement;
  endDom: HTMLElement;
}
interface IState {
  startTop: number;
  startRight: number;
  endTop: number;
  endLeft: number;
  canvasRef: React.RefObject<HTMLCanvasElement>;
}
export default class ArrowCanvasCC extends Component<IProps, IState> {
  constructor(props: IProps) {
    super(props);
    this.state = {
      startTop: 0,
      startRight: 0,
      endTop: 0,
      endLeft: 0,
      canvasRef: React.createRef<HTMLCanvasElement>(),
    };
  }

  trackElement = () => {
    const { startDom, endDom } = this.props;
    const canvasDom = this.state.canvasRef.current;
    if (canvasDom) {
      this.setState(
        {
          startTop:
            startDom.getBoundingClientRect().top -
            canvasDom.getBoundingClientRect().top,
          startRight:
            startDom.getBoundingClientRect().right -
            canvasDom.getBoundingClientRect().left,
          endTop:
            endDom.getBoundingClientRect().top -
            canvasDom.getBoundingClientRect().top,
          endLeft:
            endDom.getBoundingClientRect().left -
            canvasDom.getBoundingClientRect().left,
        },
        () => {
          this.paint();
        }
      );
    }
  };
  mouseDown = () => {
    document.addEventListener("mousemove", this.trackElement);
  };
  mouseUp = () => {
    document.removeEventListener("mousemove", this.trackElement);
  };
  componentDidMount() {
    const canvasDom = this.state.canvasRef.current;
    if (canvasDom) {
      // set canvas to cover parent
      const parent = canvasDom.parentElement;
      if (parent) {
        // let canvas cover the viewport
        canvasDom.width = parent.offsetWidth - 1; //不减1可能会出现滚动条闪烁情况
        canvasDom.height = parent.offsetHeight;
      }

      //init, set canvas and targets ready
      this.trackElement();

      window.addEventListener("resize", this.trackElement);
      document.addEventListener("mousedown", this.mouseDown);
      document.addEventListener("mouseup", this.mouseUp);
    }
  }
  componentWillUnmount() {
    window.removeEventListener("resize", this.trackElement);
    document.removeEventListener("mousedown", this.mouseDown);
    document.removeEventListener("mouseup", this.mouseUp);
  }

  paint = () => {
    // paint
    const canvasDom = this.state.canvasRef.current;
    if (canvasDom) {
      const parent = canvasDom.parentElement;
      if (parent) {
        // let canvas cover the viewport
        canvasDom.width = parent.offsetWidth - 1; //不减1可能会出现滚动条闪烁情况
        canvasDom.height = parent.offsetHeight;
      }
      const ctx = canvasDom.getContext("2d");
      if (ctx) {
        const { startRight, startTop, endLeft, endTop } = this.state;
        const { startDom, endDom } = this.props;
        drawArrow(
          ctx,
          startRight,
          startTop + startDom.offsetHeight / 2,
          endLeft,
          endTop + endDom.offsetHeight / 2,
          40,
          30,
          6,
          "rgba(243, 156, 18, 0.8)"
        );
      } else {
        console.error("sorry, currently your browser does not support canvas!");
      }
    }

    function drawArrow(
      ctx: CanvasRenderingContext2D,
      fromX: number,
      fromY: number,
      toX: number,
      toY: number,
      theta: number,
      headlen: number,
      width: number,
      color: string
    ) {
      // ctx：Canvas绘图环境
      // fromX, fromY：起点坐标（也可以换成p1，只不过它是一个数组）
      // toX, toY：终点坐标 (也可以换成p2，只不过它是一个数组)
      // theta：三角斜边&直线夹角
      // headlen：三角斜边长度
      // width：箭头线宽度
      // color：箭头颜色

      // 计算各角度和对应的P2,P3坐标
      var angle = (Math.atan2(fromY - toY, fromX - toX) * 180) / Math.PI,
        angle1 = ((angle + theta) * Math.PI) / 180,
        angle2 = ((angle - theta) * Math.PI) / 180,
        topX = headlen * Math.cos(angle1),
        topY = headlen * Math.sin(angle1),
        botX = headlen * Math.cos(angle2),
        botY = headlen * Math.sin(angle2);

      ctx.save();
      ctx.beginPath();
      var arrowX = fromX - topX,
        arrowY = fromY - topY;

      ctx.moveTo(arrowX, arrowY);
      ctx.moveTo(fromX, fromY);
      ctx.lineTo(toX, toY);
      arrowX = toX + topX;
      arrowY = toY + topY;
      ctx.moveTo(arrowX, arrowY);
      ctx.lineTo(toX, toY);
      arrowX = toX + botX;
      arrowY = toY + botY;
      ctx.lineTo(arrowX, arrowY);
      ctx.strokeStyle = color;
      ctx.lineWidth = width;
      ctx.stroke();
      ctx.restore();
    }
  };

  render() {
    const { canvasRef } = this.state;
    return (
      <canvas
        id="canvas"
        style={{
          position: "absolute",
          top: 0,
          left: 0,
          pointerEvents: "none",
        }}
        ref={canvasRef}
      >
        sorry, currently your browser does not support canvas!
      </canvas>
    );
  }
}
